/**
 * @author ming
 * @date 2021/2/14 21:20
 * @desc redis 连接信息
 */
package redis

import (
	"beego-template/g"
	"context"
	"github.com/astaxie/beego"
	"github.com/go-redis/redis/v8"
	"strings"
	"time"
)

type Client struct {
	clusterMode   bool                 //是否是集群模式
	client        *redis.Client        //单机客户段
	clusterClient *redis.ClusterClient //集群客户端
}

func (c *Client) Do(args ...interface{}) *redis.Cmd {
	if c.clusterMode {
		return c.clusterClient.Do(ctx, args...)
	} else {
		return c.client.Do(ctx, args...)
	}
}

const (
	serverMode  = "server"  //单机模式
	clusterMode = "cluster" //集群模式
)

var ctx = context.Background()

var (
	redisMode     = ""
	redisAddr     = ""
	redisPassword = ""
	redisDB       = 0

	client *Client
)

func init() {
	redisMode = beego.AppConfig.String("redis-mode")
	db, err := beego.AppConfig.Int("redis-db")
	if err == nil && db >= 0 && db <= 15 {
		redisDB = db
	}

	redisAddr = beego.AppConfig.String("redis-addr")
	redisPassword = beego.AppConfig.String("redis-password")
}

// 获取redis数据库连接
func NewRedisClient() *Client {
	if client != nil {
		return client
	}

	client = new(Client)
	if redisMode == serverMode {
		client.clusterMode = false
		client.client = newSingleClient(redisAddr, redisPassword)
	} else if redisMode == clusterMode {
		client.clusterMode = true
		client.clusterClient = newClusterClient(redisAddr, redisPassword)
	} else {
		g.Log.Error("'redis-mode' 配置信息错误")
	}

	return client
}

func newSingleClient(addr string, password string) *redis.Client {
	userName := beego.AppConfig.String("redis-username")
	dialTimeout := beego.AppConfig.DefaultInt("redis-dial-timeout", 3)
	readTimeout := beego.AppConfig.DefaultInt("redis-read-timeout", 3)
	writeTimeout := beego.AppConfig.DefaultInt("redis-write-timeout", 3)

	c := redis.NewClient(&redis.Options{
		Addr:         addr,
		Username:     userName,
		Password:     password,
		DB:           redisDB,
		PoolSize:     16,
		DialTimeout:  time.Duration(dialTimeout) * time.Second,  // 设置连接超时
		ReadTimeout:  time.Duration(readTimeout) * time.Second,  // 设置读取超时
		WriteTimeout: time.Duration(writeTimeout) * time.Second, // 设置写入超时
	})

	// 发送一个ping命令,测试是否通
	err := c.Do(ctx, "ping").Err()
	if err != nil {
		g.Log.Error("连接 redis 失败")
	}

	return c
}

func newClusterClient(addr string, password string) *redis.ClusterClient {
	userName := beego.AppConfig.String("redis-username")
	dialTimeout := beego.AppConfig.DefaultInt("redis-dial-timeout", 3)
	readTimeout := beego.AppConfig.DefaultInt("redis-read-timeout", 3)
	writeTimeout := beego.AppConfig.DefaultInt("redis-write-timeout", 3)

	clusterClient := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs:        strings.Split(addr, ","),
		Username:     userName,
		Password:     password,                                  // 设置密码
		DialTimeout:  time.Duration(dialTimeout) * time.Second,  // 设置连接超时
		ReadTimeout:  time.Duration(readTimeout) * time.Second,  // 设置读取超时
		WriteTimeout: time.Duration(writeTimeout) * time.Second, // 设置写入超时
	})

	// 发送一个ping命令,测试是否通
	err := clusterClient.Do(ctx, "ping").Err()
	if err != nil {
		g.Log.Error("连接 redis cluster 失败")
	}

	return clusterClient
}
